package repository

import (
	"errors"
	"fmt"
	"invitation/internal/model"
	"invitation/internal/repository/cache"

	"gorm.io/gorm"
)

type GameTheoryRepository interface {
	Create(gameInfoID uint, theory string) error
	Update(gameInfoID uint, theory string) error
	FindOneByGameInfoID(gameInfoID uint) (*model.GameTheory, error)
	FindListByGameInfoIDs(gameInfoIDs []uint) ([]model.GameTheory, error)
	Delete(gameInfoID uint) error
}

type gameTheoryRepository struct{ *BaseRepository }

func newGameTheoryRepository(db *gorm.DB) *gameTheoryRepository {
	return &gameTheoryRepository{
		BaseRepository: newBaseRepository(db),
	}
}

func (gtr *gameTheoryRepository) Create(gameInfoID uint, theoryExplanation string) error {
	gameTheory := &model.GameTheory{
		GameInfoID:        gameInfoID,
		TheoryExplanation: theoryExplanation,
	}
	return gtr.GetDB().Create(gameTheory).Error
}

func (gtr *gameTheoryRepository) Update(gameInfoID uint, theoryExplanation string) error {
	// 1. 获取旧数据
	var oldGameTheory model.GameTheory
	if err := gtr.GetDB().Where("game_info_id = ?", gameInfoID).First(&oldGameTheory).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return fmt.Errorf("game theory with game_info_id %d not found, cannot update", gameInfoID)
		}
		return err
	}

	// 2. 构建更新 Map
	updateData := make(map[string]interface{})

	// 3. 检查 TheoryExplanation 字段
	// 如果新值不为空字符串（零值），则进行更新
	if theoryExplanation != "" {
		updateData["theory_explanation"] = theoryExplanation // 注意使用数据库列名 (snake_case)
	}
	// 如果 theoryExplanation 为 ""，则保留旧值。

	// 4. 执行更新
	if len(updateData) == 0 {
		return nil
	}

	return gtr.GetDB().Model(&oldGameTheory).Updates(updateData).Error
}

func (gtr *gameTheoryRepository) FindOneByGameInfoID(gameInfoID uint) (*model.GameTheory, error) {
	var gameTheory model.GameTheory
	err := gtr.GetDB().Where("game_info_id = ?", gameInfoID).First(&gameTheory).Error
	if err != nil {
		return nil, err
	}
	return &gameTheory, nil
}

func (gtr *gameTheoryRepository) FindListByGameInfoIDs(gameInfoIDs []uint) ([]model.GameTheory, error) {
	var gameTheoryList []model.GameTheory
	err := gtr.GetDB().Where("game_info_id IN (?)", gameInfoIDs).Find(&gameTheoryList).Error
	if err != nil {
		return nil, err
	}
	return gameTheoryList, nil
}
func (gtr *gameTheoryRepository) Delete(gameInfoID uint) error {
	return gtr.GetDB().Delete(&model.GameTheory{}, gameInfoID).Error
}

type cachedGameTheoryRepository struct{ *BaseCachedRepository }

func newCachedGameTheoryRepository(db *gorm.DB, cache *cache.LRU, repoName string) *cachedGameTheoryRepository {
	repo := newGameTheoryRepository(db)
	return &cachedGameTheoryRepository{
		BaseCachedRepository: newBaseCachedRepository(repo, cache, repoName),
	}
}

var theoryIDKey = "theory_id"

func (cgr *cachedGameTheoryRepository) BaseRepo() *gameTheoryRepository {
	return cgr.GetBaseRepo().(*gameTheoryRepository)
}

func (cgr *cachedGameTheoryRepository) Create(gameInfoID uint, theory string) error {
	cgr.mutex.Lock()
	defer cgr.mutex.Unlock()
	if cgr.GetCache() == nil {
		return cgr.BaseRepo().Create(gameInfoID, theory)
	}
	cacheKey := cgr.GenerateCacheKey(theoryIDKey, gameInfoID)
	cgr.GetCache().Remove(cacheKey)
	return cgr.BaseRepo().Create(gameInfoID, theory)
}

func (cgr *cachedGameTheoryRepository) Update(gameInfoID uint, theory string) error {
	cgr.mutex.Lock()
	defer cgr.mutex.Unlock()

	// 调用 BaseRepo 的 Update 方法
	err := cgr.BaseRepo().Update(gameInfoID, theory)
	if err != nil {
		return err
	}

	if cgr.GetCache() == nil {
		return nil
	}

	// 清理缓存
	cacheKey := cgr.GenerateCacheKey(theoryIDKey, gameInfoID)
	cgr.GetCache().Remove(cacheKey)

	return nil
}

func (cgr *cachedGameTheoryRepository) FindOneByGameInfoID(gameInfoID uint) (*model.GameTheory, error) {
	cgr.mutex.Lock()
	defer cgr.mutex.Unlock()
	if cgr.GetCache() == nil {
		return cgr.BaseRepo().FindOneByGameInfoID(gameInfoID)
	}
	cacheKey := cgr.GenerateCacheKey(theoryIDKey, gameInfoID)
	if value, ok := cgr.GetCache().Get(cacheKey); ok {
		return value.(*model.GameTheory), nil
	}
	gameTheory, err := cgr.BaseRepo().FindOneByGameInfoID(gameInfoID)
	if err != nil {
		return nil, err
	}
	cgr.GetCache().Add(cacheKey, gameTheory)
	return gameTheory, nil
}

// 联查不缓存
func (cgr *cachedGameTheoryRepository) FindListByGameInfoIDs(gameInfoIDs []uint) ([]model.GameTheory, error) {
	return cgr.BaseRepo().FindListByGameInfoIDs(gameInfoIDs)
}
func (cgr *cachedGameTheoryRepository) Delete(gameInfoID uint) error {
	cgr.mutex.Lock()
	defer cgr.mutex.Unlock()
	if cgr.GetCache() == nil {
		return cgr.BaseRepo().Delete(gameInfoID)
	}
	cacheKey := cgr.GenerateCacheKey(theoryIDKey, gameInfoID)
	cgr.GetCache().Remove(cacheKey)
	return cgr.BaseRepo().Delete(gameInfoID)
}

func NewGameTheoryRepositoryWithCache(db *gorm.DB, cache *cache.LRU, repoName string) Repository {
	return newCachedGameTheoryRepository(db, cache, repoName)
}
